#include <iostream>
#include <string>
#include <cstring>
using std::cout;
using std::endl;
using std::string;
using std::ostream;
using std::cerr;

class CowString{
private:
    char* _pstr;
    /* int need 4B */
    static const int kRefCntLength = 4;

    /**
     * 必须将此类私有，不可对外开放创建此类
     */
    class CharProxy{
    public:
        CharProxy(CowString &self, int idx): _self(self), _idx(idx){
        }

        char operator=(char ch);
        friend ostream& operator<<(ostream& os, const CharProxy& rhs);
    private:
        /* 指向外部类的引用 */
        CowString& _self;
        int _idx;
    };

public:
    CowString();
    CowString(const char* pstr);
    CowString(const CowString& rhs);
    CowString& operator=(const CowString& rhs);
    ~CowString();

    CharProxy operator[](int index);
    friend ostream& operator<<(ostream& os, const CowString& rhs);
    friend ostream& operator<<(ostream& os, const CharProxy& rhs);

    int size() const{
        return strlen(_pstr);
    }
    const char* c_str() const{
        return _pstr;
    }

    int useCount(){
        return *(int*)(_pstr - kRefCntLength);
    }



private:
    void initRefCnt(){
        *(int*)(_pstr - kRefCntLength) = 1;
    }
    void increaseRefCnt(){
        (*(int*)(_pstr - kRefCntLength))++;
    }
    void decreaseRefCnt(){
        (*(int*)(_pstr - kRefCntLength))--;
    }
    char* malloc_fake(const char* pstr = nullptr){
        if(pstr){
            return new char[strlen(pstr) + 1 + kRefCntLength] + kRefCntLength;
        }
        return new char[1 + kRefCntLength] + kRefCntLength;
    }

    void release(){
        decreaseRefCnt();
        if(useCount() == 0){
            delete [] (_pstr - kRefCntLength);
            _pstr = nullptr;
            cout << "release" << endl;
        }
    }
};

/**
 * 重载输出流
 * @param os
 * @param rhs
 * @return
 */
ostream& operator<<(ostream& os, const CowString& rhs){
    os << rhs._pstr;
    return os;
}


/**
 * 无参构造
 */
CowString::CowString(){
    /**
     * 4B存放引用计数
     * 1B存放null
     */
    _pstr = malloc_fake();
    initRefCnt();
    cout << "constructor" << endl;
}


/**
 * 析构
 */
CowString::~CowString(){
    release();
}

/**
 * 拷贝构造
 * @param rhs
 */
CowString::CowString(const CowString& rhs) {
    /* 浅拷贝 */
    _pstr = rhs._pstr;
    increaseRefCnt();
    cout << "copy constructor" << endl;
}

/**
 * c风格有参构造
 * @param pstr
 */
CowString::CowString(const char *pstr):_pstr(malloc_fake(pstr)) {
    initRefCnt();
    strcpy(_pstr, pstr);
    cout << "char* constructor" << endl;
}

/**
 * 重载赋值运算符
 * @param rhs
 * @return
 */
CowString& CowString::operator=(const CowString& rhs){
    if (this != &rhs){  /* 禁止自娱自乐(自赋值) */
        release();  /* 尝试回收 */
        _pstr = rhs._pstr;   /* 浅拷贝 */
        increaseRefCnt();   /* 引用计数加一 */
    }
    return *this;
}

/**
 * CharProxy 对象保存一个下标和一个引用向上绑定str1
 * @param index
 * @return 返回一个拷贝构造，默认拷贝构造为浅拷贝
 * @brief []运算符只有两种情况：读取值和修改值，所以返回一个栈上的拷贝构造没有问题，不会内存泄漏
 */
CowString::CharProxy CowString::operator[](int index){
    /*
     * index 为传入的下标
     */
    return CharProxy(*this, index);
}

/**
 * 为外部类提供内部类的赋值运算符的重载来为string[index]赋值
 * @param ch
 * @return
 */
char CowString::CharProxy::operator=(char ch) {
    if(_idx >= 0 && _idx < _self.size()){
        if(_self.useCount() > 1){
            /* 原来的引用计数-1 */
            _self.decreaseRefCnt();
            /* 深拷贝 */
            char* ptemp = _self.malloc_fake(_self._pstr);
            strcpy(ptemp, _self._pstr);
            /* 修改指向 */
            _self._pstr = ptemp;
            /* 新的空间，初始化引用计数 */
            _self.initRefCnt();
        }

        /* 执行写操作 */
        _self._pstr[_idx] = ch;
        return _self._pstr[_idx];
    }
    cerr << "out of range" << endl;
    /**
     * 返回引用时必须要加static
     */
    char nullchar = '\0';
    return nullchar;
}

/**
 * 为外部类提供内部类的输出流运算符重载用来读取string[index]的值
 * @param os
 * @param rhs
 * @return
 */
ostream& operator<<(ostream& os, const CowString::CharProxy & rhs){
    if(rhs._idx >= 0 && rhs._idx < rhs._self.size()){
        os << rhs._self._pstr[rhs._idx];
    }else{
        os << "out of range" << endl;
    }
    return os;
}



/**
 * 测试基本的复制、赋值
 */
void test0(){
    CowString string1;
    CowString string2 = string1;
    cout << string1.useCount() << endl;
    cout << string1 << endl;

    string1 = string1;
    cout << string1.useCount() << endl;
    cout << string2.useCount() << endl;
}

/**
 * 测试下标访问
 */
void test1(){
    CowString string1("hello");
    string1.operator[](3) = 'H';
    cout << string1.operator[](3) << endl;
    cout << string1 << endl;
}

int main() {
    test1();
    return 0;
}